package framework.config;

import framework.exceptions.BusinessException;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;

/**
 * 安全配置项
 */
@Slf4j
@Data
@Configuration
@ConfigurationProperties(prefix = "sys.security")
public class SecurityConfig implements InitializingBean {

    /**
     * 验证
     */
    private String authIdentityHeader = "X-AUTH-IDENTITY";

    /**
     * TOKEN过期提醒秒值
     */
    private Integer tokenExpirationReminderSeconds = 0;

    /**
     * TOKEN过期提醒百分比
     */
    private Double tokenExpirationReminderPercent = 0.0D;

    /**
     * TOKEN过期提醒头
     */
    private String tokenExpirationReminderHeader = "X-TOKEN-EXPIRES";

    /**
     * TOKEN过期余量输出
     */
    private String tokenBalanceOutputHeader;

    /**
     * 调试用的账户ID(始终使用该ID进行系统登录）
     */
    private Long debugAccountId;

    /**
     * 新密码使用的加密模式
     */
    private String passwordMode;

    /**
     * token安全密钥
     */
    private String tokenSecret;

    /**
     * token安全密钥应用索引
     */
    private Integer tokenSecretIndex = 0;

    /**
     * Token有效时长（秒）
     */
    private Integer tokenSeconds;

    /**
     * 登入地址
     */
    private String loginPath = "/auth/login";

    /**
     * 登出地址
     */
    private String logoutPath = "/auth/logout";

    /**
     * 是否启用 basic auth
     */
    private Boolean enableBasicAuth = false;

//    /**
//     * 是否启用 basic oauth
//     */
//    private Boolean enableBasicOauth = false;

    /**
     * 是否启用 WWW-Authenticate
     */
    private Boolean enableWwwAuthenticate = false;

    /**
     * 是否启用 bearer token
     */
    private Boolean enableBearerToken = true;

    /**
     * 是否启用安全组件
     */
    private Boolean enable = true;

    /**
     * 安全组件写入TOKEN/SESSION时的cookie存储路径
     */
    private String cookiePath = null;

    /**
     * 安全组件写入TOKEN/SESSION时的cookie存储域名
     */
    private String cookieDomain = null;

    /**
     * 安全组件写入TOKEN/SESSION时的cookie secure
     */
    private Boolean cookieSecure = false;

    /**
     * 安全组件写入TOKEN/SESSION时的cookie secure
     */
    private Boolean cookieHttpOnly = false;

    /**
     * 安全组件写入TOKEN/SESSION时的cookie max age
     */
    private Integer cookieMaxAge;

    /**
     * 自动续期COOKIE中TOKEN的时间百分比，0-100，建议有效期到达60%时更新，0关闭:
     */
    private Integer cookieTokenRenew = 0;

    /**
     * 安全组件写入TOKEN/SESSION时的cookie same site
     */
    private String cookieSameSite;

    /**
     * 安全组件将TOKEN写入cookie的cookie name，以及请求授权时的请求参数名称
     */
    private String tokenParamName = "TOKEN";

    /**
     * 记录我的最大是间值（秒），0则不启用
     */
    private Integer rememberMeMaxSeconds = 0;

    /**
     * 是否启用登录验证码
     */
    private Boolean enableLoginCaptcha = false;

    /**
     * 是否启用CSRF
     */
    private Boolean enableCsrf = false;

    /**
     * 需要授权才能访问的路径
     */
    private String pathAuthList = null;

    /**
     * 允许匿名访问的路径
     */
    private String pathAnonList = null;

    /**
     * 授权过程中出现未处理异常
     */
    private String redirectOnAuthError = null;
    /**
     * 授权失败时的重定向地址
     */
    private String redirectOnAuthFailed = null;
    /**
     * 授权成功时的重定向地址
     */
    private String redirectOnAuthSuccess = null;
    /**
     * 登出后的重定向地址
     */
    private String redirectOnLogoutSuccess = null;
    /**
     * 未登录时的重定向地址
     */
    private String redirectOnNoAuth = null;
    /**
     * 无权限时的重定向地址
     */
    private String redirectOnNoPermission = null;
    /**
     * 是否验证cors
     */
    private Boolean corsAuth = false;

    @Override
    public void afterPropertiesSet() {
        if (tokenSecret == null || tokenSecret.isEmpty()) {
//            byte[] bytes = new byte[50];
//            new SecureRandom().nextBytes(bytes);
//            tokenSecret = Base64.getEncoder().encodeToString(bytes).substring(0, 32);

            try {
                // 获取主机名称
                StringBuffer buffer = new StringBuffer();
                String hostName = InetAddress.getLocalHost().getHostName();
                Enumeration<NetworkInterface> nis = NetworkInterface.getNetworkInterfaces();
                while (nis.hasMoreElements()) {
                    NetworkInterface ni = nis.nextElement();
                    String displayName = ni.getDisplayName();
                    buffer.append(displayName).append("\n");
                    Enumeration<InetAddress> inetAddresses = ni.getInetAddresses();
                    while (inetAddresses.hasMoreElements()) {
                        InetAddress inetAddress = inetAddresses.nextElement();
                        String hostAddress = inetAddress.getHostAddress();
                        buffer.append(hostAddress).append("\n");
                    }
                }

                //
                tokenSecret = org.apache.commons.codec.digest.DigestUtils.md5Hex(buffer.toString());

                //
                log.warn("Generate dynamic security key: " + tokenSecret + ", your can fixed config token-secret in application.yml");
            } catch (Exception exception) {
                throw new BusinessException("Generate security.token-secret failed, your can config token-secret in application.yml", exception);
            }
        }
    }

}
